/***************************************************************************//**
 * @file HID/HID_Controls.cpp
 * @author  Marek M. Cel <marekcel@mscsim.org>
 *
 * @section LICENSE
 *
 * Copyright (C) 2013 Marek M. Cel
 *
 * This file is part of MScSim. You can redistribute and modify it under
 * the terms of GNU General Public License as published by the Free Software
 * Foundation; either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.
 * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * Further information about the GNU General Public License can also be found
 * on the world wide web at http://www.gnu.org.
 ******************************************************************************/
#ifndef HID_CONTROLS_CPP
#define HID_CONTROLS_CPP
#endif

////////////////////////////////////////////////////////////////////////////////

#include <HID/HID_Controls.h>

////////////////////////////////////////////////////////////////////////////////

using namespace std;

////////////////////////////////////////////////////////////////////////////////

HID_Controls::HID_Controls() :
    m_speedCtrl      ( 1.0f ),
    m_speedTrim      ( 1.0f ),
    m_speedBrakes    ( 1.0f ),
    m_speedGear      ( 0.5f ),
    m_speedFlaps     ( 0.5f ),
    m_speedAirbrake  ( 1.0f ),
    m_speedSpoilers  ( 1.0f ),
    m_speedThrottle  ( 0.5f ),
    m_speedMixture   ( 0.5f ),
    m_speedPropeller ( 0.5f )
{
    for ( int i = 0; i < MSCSIM_HID_ACTIONS; i++ )
    {
        m_actions[ i ].assignment = None;
        
        m_actions[ i ].keyId = 0;
        
        m_actions[ i ].joystickId = 0;
        m_actions[ i ].axisId     = 0;
        m_actions[ i ].buttonId   = 0;
        m_actions[ i ].inverted   = 0;
    }
    
    reset();
}

////////////////////////////////////////////////////////////////////////////////

HID_Controls::~HID_Controls() {}

////////////////////////////////////////////////////////////////////////////////

void HID_Controls::init( void * winId )
{
    HID_Joysticks::getInstance()->init( winId );
}

////////////////////////////////////////////////////////////////////////////////

void HID_Controls::update( double timeStep )
{
    m_timeStep = (float)timeStep;
    
    updateNonAxisActions();
    
    for ( int i = 0; i < MSCSIM_HID_ENGINES; i++ )
    {
        m_throttles  [ i ] = m_commonThrottle;
        m_mixtures   [ i ] = m_commonMixture;
        m_propellers [ i ] = m_commonPropeller;
    }
    
    updateAxisActions();
}

////////////////////////////////////////////////////////////////////////////////

void HID_Controls::getJoyAxisValue( const Action & action, float & value, int absolute )
{
    if ( action.assignment == Joystick )
    {
        if ( ( action.joystickId >= 0 ) && ( action.axisId >= 0 ) )
        {
            HID_Joysticks::Data joyData = HID_Joysticks::getInstance()->getJoyData( action.joystickId );
            
            if ( joyData.active )
            {
                value = joyData.axis[ action.axisId ];
                
                if ( action.inverted ) value *= -1.0f;
                
                if ( absolute ) value = ( value + 1.0f ) / 2.0f;
            }
        }
    }
}

////////////////////////////////////////////////////////////////////////////////

void HID_Controls::getKeyAxisValue( int decreaseAction,
                                int increaseAction,
                                float & value,
                                float speed,
                                float min,
                                float max )
{
    int tempDecrease = 0;
    int tempIncrease = 0;
    
    getJoyButtState( m_actions[ decreaseAction ] , tempDecrease );
    getJoyButtState( m_actions[ increaseAction ] , tempIncrease );
    
    if ( tempDecrease && value > min ) value = value - speed * m_timeStep;
    if ( tempIncrease && value < max ) value = value + speed * m_timeStep;
    
    if ( value < min ) value = min;
    if ( value > max ) value = max;
}

////////////////////////////////////////////////////////////////////////////////

void HID_Controls::getJoyButtState( const Action &/*action*/, int &/*state*/ )
{

}

////////////////////////////////////////////////////////////////////////////////

void HID_Controls::reset()
{
    m_timeStep = 0.0f;
    
    m_ctrlRoll  = 0.0f;
    m_ctrlPitch = 0.0f;
    m_ctrlYaw   = 0.0f;
    
    m_trimRoll  = 0.0f;
    m_trimPitch = 0.0f;
    m_trimYaw   = 0.0f;
    
    m_brakeLeft  = 0.0f;
    m_brakeRight = 0.0f;
    
    m_commonGear = 0.0f;
    
    for ( int i = 0; i < 3; i++ )
    {
        m_gear[ i ] = 0.0f;
    }
    
    m_flaps    = 0.0f;
    m_airbrake = 0.0f;
    m_spoilers = 0.0f;
    
    m_collective = 0.0f;
    
    m_commonThrottle  = 0.0f;
    m_commonMixture   = 0.0f;
    m_commonPropeller = 0.0f;
    
    for ( int i = 0; i < MSCSIM_HID_ENGINES; i++ )
    {
        m_throttles  [ i ] = 0.0f;
        m_mixtures   [ i ] = 0.0f;
        m_propellers [ i ] = 0.0f;
    }
    
    m_parkingBrake = 0;
    m_landingGear  = 0;
}

////////////////////////////////////////////////////////////////////////////////

void HID_Controls::updateAxisActions()
{
    getJoyAxisValue( m_actions[ RollAxis  ] , m_ctrlRoll  );
    getJoyAxisValue( m_actions[ PitchAxis ] , m_ctrlPitch );
    getJoyAxisValue( m_actions[ YawAxis   ] , m_ctrlYaw   );
    
    getJoyAxisValue( m_actions[ TrimRollAxis  ] , m_trimRoll  );
    getJoyAxisValue( m_actions[ TrimPitchAxis ] , m_trimPitch );
    getJoyAxisValue( m_actions[ TrimYawAxis   ] , m_trimYaw   );
    
    getJoyAxisValue( m_actions[ BrakeLeftAxis  ] , m_brakeLeft  , 1 );
    getJoyAxisValue( m_actions[ BrakeRightAxis ] , m_brakeRight , 1 );
    
    getJoyAxisValue( m_actions[ CollectiveAxis ] , m_collective , 1 );
    
#   if ( MSCSIM_HID_ENGINES != 4 )
#   error 'MSCSIM_HID_ENGINES' has been changed! Check code following this line!
#   endif

    getJoyAxisValue( m_actions[ ThrottleAxis1 ] , m_throttles[ 0 ] , 1 );
    getJoyAxisValue( m_actions[ ThrottleAxis2 ] , m_throttles[ 1 ] , 1 );
    getJoyAxisValue( m_actions[ ThrottleAxis3 ] , m_throttles[ 2 ] , 1 );
    getJoyAxisValue( m_actions[ ThrottleAxis4 ] , m_throttles[ 3 ] , 1 );
    
    getJoyAxisValue( m_actions[ MixtureAxis1 ] , m_mixtures[ 0 ] , 1 );
    getJoyAxisValue( m_actions[ MixtureAxis2 ] , m_mixtures[ 1 ] , 1 );
    getJoyAxisValue( m_actions[ MixtureAxis3 ] , m_mixtures[ 2 ] , 1 );
    getJoyAxisValue( m_actions[ MixtureAxis4 ] , m_mixtures[ 3 ] , 1 );
    
    getJoyAxisValue( m_actions[ PropellerAxis1 ] , m_propellers[ 0 ] , 1 );
    getJoyAxisValue( m_actions[ PropellerAxis2 ] , m_propellers[ 1 ] , 1 );
    getJoyAxisValue( m_actions[ PropellerAxis3 ] , m_propellers[ 2 ] , 1 );
    getJoyAxisValue( m_actions[ PropellerAxis4 ] , m_propellers[ 3 ] , 1 );
}

////////////////////////////////////////////////////////////////////////////////

void HID_Controls::updateNonAxisActions()
{
    if ( m_actions[ RollAxis  ].assignment == None ) getKeyAxisValue( RollBankLeft , RollBankRight , m_ctrlRoll  , m_speedCtrl , -1.0f , 1.0f );
    if ( m_actions[ PitchAxis ].assignment == None ) getKeyAxisValue( PitchNoseUp  , PitchNoseDown , m_ctrlPitch , m_speedCtrl , -1.0f , 1.0f );
    if ( m_actions[ YawAxis   ].assignment == None ) getKeyAxisValue( YawTurnLeft  , YawTurnRight  , m_ctrlYaw   , m_speedCtrl , -1.0f , 1.0f );
    
    if ( m_actions[ TrimRollAxis  ].assignment == None ) getKeyAxisValue( TrimRollBankLeft , TrimRollBankRight , m_trimRoll  , m_speedTrim , -1.0f , 1.0f );
    if ( m_actions[ TrimPitchAxis ].assignment == None ) getKeyAxisValue( TrimPitchNoseUp  , TrimPitchNoseDown , m_trimPitch , m_speedTrim , -1.0f , 1.0f );
    if ( m_actions[ TrimYawAxis   ].assignment == None ) getKeyAxisValue( TrimYawTurnLeft  , TrimYawTurnRight  , m_trimYaw   , m_speedTrim , -1.0f , 1.0f );
    
    if ( m_actions[ BrakeLeftAxis ].assignment == None )
    {
        int tempIncrease = 0;
        
        getJoyButtState( m_actions[ BrakeLeftApply ] , tempIncrease );
        
        if ( !tempIncrease && m_brakeLeft > 0.0f ) m_brakeLeft = m_brakeLeft - m_speedBrakes * m_timeStep;
        if (  tempIncrease && m_brakeLeft < 1.0f ) m_brakeLeft = m_brakeLeft + m_speedBrakes * m_timeStep;
        
        if ( m_brakeLeft < 0.0f ) m_brakeLeft = 0.0f;
        if ( m_brakeLeft > 1.0f ) m_brakeLeft = 1.0f;
    }
    
    if ( m_actions[ BrakeRightAxis ].assignment == None )
    {
        int tempIncrease = 0;
        
        getJoyButtState( m_actions[ BrakeRightApply ] , tempIncrease );
        
        if ( !tempIncrease && m_brakeRight > 0.0f ) m_brakeRight = m_brakeRight - m_speedBrakes * m_timeStep;
        if (  tempIncrease && m_brakeRight < 1.0f ) m_brakeRight = m_brakeRight + m_speedBrakes * m_timeStep;
        
        if ( m_brakeRight < 0.0f ) m_brakeRight = 0.0f;
        if ( m_brakeRight > 1.0f ) m_brakeRight = 1.0f;
    }
}
